#ifndef     __SOCKET_H_INCLUDED__
#define     __SOCKET_H_INCLUDED__

#include	<string>

#define		IO_NONE			0
#define		IO_READ			1
#define		IO_WRITE		2
#define		IO_READWRITE	3

/**
 * TCP socket to remove platform dependency.
 */
struct Socket {
	int ctx;

	Socket();
	virtual ~Socket();

	/**
	 * Connect to TCP server.
	 *
	 * \param ip IP address of remote server.
	 * \param port Port to connect to.
	 * \return Is connected with remote server successfully?
	 */
	bool Connect(const std::string & ip, int port);

	/**
	 * Listen on given address for connections.
	 *
	 * \param ip Bind listen ip.
	 * \param port Port to listen on.
	 * \return Is listen on given address successfully?
	 */
	bool Listen(const std::string & ip, int port);

	/**
	 * Accept connection request.
	 *
	 * \return Accepted client socket. nullptr for no request coming.
	 */
	Socket * Accept();

	/**
	 * Receive data.
	 *
	 * \param buf Buffer pointer to store received data.
	 * \param size Buffer's size in bytes.
	 * \return >0 : valid received data size. =0 : data pending, should wait. -1 : peer closed. -2 : error whild reading data.
	 */
	int Recv(char * buf, size_t size);

	/**
	 * Send data to remote server/client.
	 *
	 * \param data Buffer stores data to be sent.
	 * \param size Size of data in bytes to be sent.
	 * \return Send successfully?
	 */
	bool Send(const char * data, size_t size);

	/**
	 * Close connection.
	 */
	void Close();
};

/** Interface for listen socket IO event */
struct IOListener {
	virtual ~IOListener() {}

	/**
	 * Bind listener on given file descriptor(or SOCKET on windows)
	 *
	 * \param fd File descriptor or SOCKET on windows.
	 * \param events Listen events.
	 */
	void BindIO(int fd, int events);

	/**
	 * Wait for given events be raised once. 
	 *
	 * \param event Event type waiting raised.
	 */
	void WaitIO(int event);

	/** Unbind listener on attached file descriptor */
	void UnbindIO();

	/** Interface to handle readable event */
	virtual void OnReadable() {};

	/** Interface to handle writable event */
	virtual void OnWritable() {};

private:
	int _binded_io_fd;
};

/**
 * Breath all sockets
 */
extern void BreathAllSockets();

#endif//!   __SOCKET_H_INCLUDED__